from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models import User, BalanceLog
from app.schemas import UserCreate, BalanceLogType
from typing import Optional
from app.config import settings
import logging

logger = logging.getLogger(__name__)


class UserService:
    
    @staticmethod
    async def create_user(db: AsyncSession, user_data: UserCreate) -> User:
        """Create a new user with initial balance"""
        user = User(
            username=user_data.username,
            balance=settings.initial_balance
        )
        
        db.add(user)
        await db.commit()
        await db.refresh(user)
        
        logger.info(f"Created user {user.id} with username '{user.username}' and initial balance {settings.initial_balance}")
        return user
    
    @staticmethod
    async def get_user(db: AsyncSession, user_id: str) -> Optional[User]:
        """Get user by ID"""
        result = await db.execute(select(User).where(User.id == user_id))
        return result.scalar_one_or_none()
    
    @staticmethod
    async def get_user_by_username(db: AsyncSession, username: str) -> Optional[User]:
        """Get user by username"""
        result = await db.execute(select(User).where(User.username == username))
        return result.scalar_one_or_none()
    
    @staticmethod
    async def update_balance(
        db: AsyncSession, 
        user_id: str, 
        amount: float, 
        log_type: BalanceLogType,
        contract_id: str = None
    ) -> User:
        """Update user balance and create balance log"""
        user = await UserService.get_user(db, user_id)
        if not user:
            raise ValueError(f"User {user_id} not found")
        
        balance_before = user.balance
        balance_after = balance_before + amount
        
        if balance_after < 0:
            raise ValueError("Insufficient balance")
        
        # Update user balance
        user.balance = balance_after
        
        # Create balance log
        balance_log = BalanceLog(
            user_id=user_id,
            contract_id=contract_id,
            amount=amount,
            balance_before=balance_before,
            balance_after=balance_after,
            type=log_type.value
        )
        
        db.add(balance_log)
        await db.commit()
        await db.refresh(user)
        
        logger.info(f"Updated balance for user {user_id}: {balance_before} -> {balance_after} (amount: {amount}, type: {log_type.value})")
        return user
    
    @staticmethod
    async def get_balance_logs(db: AsyncSession, user_id: str, limit: int = 100) -> list[BalanceLog]:
        """Get user balance logs"""
        result = await db.execute(
            select(BalanceLog)
            .where(BalanceLog.user_id == user_id)
            .order_by(BalanceLog.created_at.desc())
            .limit(limit)
        )
        return result.scalars().all()
    
    @staticmethod
    async def check_sufficient_balance(db: AsyncSession, user_id: str, amount: float) -> bool:
        """Check if user has sufficient balance"""
        user = await UserService.get_user(db, user_id)
        if not user:
            return False
        return user.balance >= amount
